package com.avengers.core.kit;

import com.avengers.core.bean.enums.SymbolEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.util.function.Supplier;

import static com.avengers.core.bean.Numbers.INT_2;
import static com.avengers.core.bean.Numbers.INT_3;

/**
 * @author wy
 * @since 11:29 2018/6/1
 */
public class TimeKit {
    private static final Logger logger = LoggerFactory.getLogger(TimeKit.class);

    public static BigDecimal useTimeSecond(Long beginNanoTime) {
        return BigDecimal.valueOf((System.nanoTime() - beginNanoTime) / 1000000000.0).setScale(INT_2, RoundingMode.HALF_UP);
    }

    public static BigDecimal useTimeMillisecond(Long beginNanoTime) {
        return BigDecimal.valueOf((System.nanoTime() - beginNanoTime) / 1000000.0).setScale(INT_3, RoundingMode.HALF_UP);
    }

    public static String useTimeStr(Long useMillisecond) {
        StringBuilder sb = new StringBuilder();
        long days = useMillisecond / (1000 * 60 * 60 * 24);
        long hours = (useMillisecond / (1000 * 60 * 60)) % 24;
        long minutes = (useMillisecond / (1000 * 60)) % 60;
        long seconds = (useMillisecond / 1000) % 60;
        long milliseconds = useMillisecond % 1000;
        if (days > 0) {
            sb.append(days).append("天");
        }
        if (hours > 0) {
            sb.append(hours).append("小时");
        }
        if (minutes > 0) {
            sb.append(minutes).append("分钟");
        }
        if (seconds > 0) {
            sb.append(seconds).append("秒");
        }
        if (milliseconds > 0) {
            sb.append(milliseconds).append("毫秒");
        }
        return sb.toString();
    }

    public static boolean isHourMatch(String matchHourStr, LocalTime localTime) {
        if (StringKit.isBlank(matchHourStr)) {
            return true;
        }
        for (String timeStr : matchHourStr.split(SymbolEnum.comma.string)) {
            String min = timeStr.split(SymbolEnum.minus.string)[0];
            String max = timeStr.split(SymbolEnum.minus.string)[1];
            if (localTime.isAfter(localTimeByHour(min)) && localTime.isBefore(localTimeByHour(max))) {
                return true;
            }
        }
        return false;
    }

    private static LocalTime localTimeByHour(String hourStr) {
        int zero = 0;
        int hour = Integer.parseInt(hourStr);
        if (hour < zero || hour > LocalTime.MAX.getHour()) {
            return LocalTime.MAX;
        }
        return LocalTime.of(hour, zero, zero);
    }

    public static void logUsedTime(Runnable runnable) {
        logUsedTime(runnable, null);
    }

    public static void logUsedTime(Runnable runnable, Logger logger) {
        logUsedTime(runnable, logger, null);
    }

    public static void logUsedTime(Runnable runnable, String logMsg, Object... args) {
        logUsedTime(runnable, logger, logMsg, args);
    }

    public static void logUsedTime(Runnable runnable, Logger logger, String logMsg, Object... args) {
        logUsedTime(() -> {
            runnable.run();
            return null;
        }, logger, logMsg, args);
    }

    public static <T> T logUsedTime(Supplier<T> supplier) {
        return logUsedTime(supplier, null);
    }

    public static <T> T logUsedTime(Supplier<T> supplier, Logger logger) {
        return logUsedTime(supplier, logger, null);
    }

    public static <T> T logUsedTime(Supplier<T> supplier, String logMsg, Object... args) {
        return logUsedTime(supplier, logger, logMsg, args);
    }

    public static <T> T logUsedTime(Supplier<T> supplier, Logger logger, String logMsg, Object... args) {
        long beginNanoTime = System.currentTimeMillis();
        final Logger finalLogger = null == logger ? TimeKit.logger : logger;
        try {
            return supplier.get();
        } finally {
            try {
                BigDecimal useTimeMillisecond = new BigDecimal(System.currentTimeMillis() - beginNanoTime);
                if (StringKit.notBlank(logMsg)) {
                    String finalMsg = logMsg + " use: {}ms({})";
                    final Object[] logArgs;
                    if (null != args) {
                        logArgs = new Object[args.length + 2];
                        System.arraycopy(args, 0, logArgs, 0, args.length);
                    } else {
                        logArgs = new Object[2];
                    }
                    logArgs[logArgs.length - 2] = useTimeMillisecond.longValue();
                    logArgs[logArgs.length - 1] = useTimeStr(useTimeMillisecond.longValue());
                    finalLogger.info(finalMsg, logArgs);
                } else {
                    finalLogger.info("use: {}ms({})", useTimeMillisecond.longValue(), useTimeStr(useTimeMillisecond.longValue()));
                }
            } catch (Exception e) {
                finalLogger.error("log use time error: {}", e.getMessage(), e);
            }
        }
    }
}
